#include "SystemInit.h"
#include "CommProtocol.h"
#include "stm32f10x.h"
#include "Flash.h"
#include "FlashPartition.h"
#include "string.h"

#define APPLICATION_NAME "Ota-test"			//应用程序名


bool IsUpdateFlagSet(void)
{
	bool bUpdate = false;
	//读取RAM中升级标识地址内容
	uint16_t nFlag = *((__IO uint16_t *)UPDATE_FLAG_ADDRESS);
	//判断从RAM中读出的内容是否为升级标识
	if (UPDATE_FLAG == nFlag)
	{
		bUpdate = true;
	}
	return bUpdate;
}


bool IsApplcaitonProgramValid(void)
{
	uint8_t nLen1 = strlen(APPLICATION_NAME);
	uint8_t buff[14] = {0};
	bool bSuccess = Flash_Read(VALID_STRING_ADDRESS, buff, sizeof(buff));
	if (!bSuccess)		//读Flash失败
	{
		return false;
	}
	
	if (nLen1 != strlen((const char*)buff))//标志长度不一致
	{
		return false;
	}
	
	if (0 != strncmp((const char*)buff, APPLICATION_NAME, nLen1))//标识长度不一致
	{
		return false;
	}
	
	uint16_t nCrc1 = 0x00;
	bSuccess = Flash_Read(CRC_SUM_ADDRESS, (uint8_t*)(&nCrc1), 2);		//读Flash中的CRC校验值
	
	uint16_t nCrc2 = 0xFFFF;
	for(int i = 0; i < APPLICATION_PARTITION_SIZE - 2; i++)
	{
		uint8_t data;
		bool bSuccess = Flash_Read(APPLICATION_PARTITION_ADDRESS + i, &data, 1);
		if (!bSuccess)
		{
			return false;
		}
		// 将当前字节与CRC值的高8位进行异或操作。
        nCrc2 ^= data << 8;
        // 对每个字节处理8次，对应8位。
        for (int j = 0; j < 8; ++j) 
		{
            // 检查CRC值的最高位是否为1。
            if (nCrc2 & 0x8000) {
                // 如果最高位为1，将CRC值左移1位后与多项式0x1021进行异或。
                nCrc2 = (nCrc2 << 1) ^ 0x1021;
            } else {
                // 如果最高位不为1，仅将CRC值左移1位。
                nCrc2 <<= 1;
            }
        }
	}
	
	if (nCrc1 == nCrc2)
	{
		return true;
	}
	else
	{
		return false;
	}
}

#ifdef __cplusplus
extern "C" {
#endif
void Go2Application(void)
{
	uint32_t jumpAddr;		//跳转地址，程序开始地址
	
	pFunc Jump2App;			//跳转函数
	
	//检查栈顶地址是否合法
	if (((*(__IO uint32_t *)APPLICATION_PARTITION_ADDRESS) & 0x2FFE0000) == 0x20000000)
	{
		//屏蔽所有中断，防止在跳转过程中，中断干扰出现异常
		__disable_irq();
		//应用代码区第二个字节为程序开始地址（复位地址）
		jumpAddr = *(__IO uint32_t *)(APPLICATION_PARTITION_ADDRESS + 4);
		//初始化堆栈指针（程序代码区第一个字用于存放栈顶地址）
		__set_MSP(* (__IO uint32_t *)APPLICATION_PARTITION_ADDRESS);
		//转换为函数指针
		Jump2App = (pFunc)jumpAddr;
		//执行跳转函数
		Jump2App();
	}
}


void Go2Update(void)
{
	//通知服务器，MCU端进入了升级模式
	SendMessage(enumCmdFromMcu2Server_EnterUpgrade, NULL, 0);
}

void SoftwareReset(void)
{
	__set_FAULTMASK(1);			//关闭所有中断
	NVIC_SystemReset();			//触发系统复位	
}	

#ifdef __cplusplus
}
#endif

void System_Init(void)
{
	CommProtocol_Init();
}


